package org.jeecg.modules.flowable.util;

import com.google.common.collect.Lists;
import org.flowable.bpmn.model.*;
import org.jeecg.modules.flowable.common.util.validation.AssertValid;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Title:  <br>
 * Desc:  <br>
 * Date: 6/23/22 11:38 AM <br>
 * Company: 联通（辽宁）产业互联网有限公司 <br>
 *
 * @author zxd
 * @version 1.0.0
 */
public class FlowableUtil {
    /**
     * 递归查找上一级节点列表
     * @param flowElements
     * @param currTaskKey
     * @return
     */
    public static List<UserTask> getParentUserTaskList(Collection<FlowElement> flowElements, String currTaskKey,List<String> argAlSf) {
        List<UserTask> taskList = Lists.newArrayList();
        // 查找当前组件下有几条线
        if(argAlSf==null)
            argAlSf = Lists.newArrayList();
        List<SequenceFlow> sfList = Lists.newArrayList();
        for (FlowElement flowElement : flowElements) {
            if(flowElement instanceof SequenceFlow && ((SequenceFlow) flowElement).getTargetRef().toString().equals(currTaskKey)){
                if(!argAlSf.contains(((SequenceFlow) flowElement).getId())) {
                    sfList.add((SequenceFlow)flowElement);
                    argAlSf.add(((SequenceFlow) flowElement).getId());
                }
            }
        }
        // 针对多条线儿进行循环
        for (SequenceFlow sequenceFlow : sfList) {
            String sourceRef = ((SequenceFlow) sequenceFlow).getSourceRef();
            f:for (FlowElement flowElement : flowElements) {
                if(flowElement.getId().toString().equals(sourceRef)) {
                    if (flowElement instanceof UserTask) {
                        taskList.add((UserTask) flowElement);
                        break f;
                    } else {
                        // 如果是非用户任务，则继续往下查找用户任务
                        List<UserTask> backUserTaskKey = getParentUserTaskList(flowElements, flowElement.getId(),argAlSf);
                        taskList.addAll(backUserTaskKey);
                        return taskList;
                    }
                }
            }
        }
        return taskList;
    }

    /**
     * 递归查找当前执行节点前的所有节点
     * @param flowElements
     * @param currTaskKeys
     * @param lineFilter 过滤掉线儿
     * @param argAlSf 已经循环过的线儿ID就不在进行循环了
     * @return
     */
    public static List<FlowElement> getParenElementList(Collection<FlowElement> flowElements, List<String> currTaskKeys,Boolean lineFilter,List<String> argAlSf) {
        List<FlowElement> taskList = Lists.newArrayList();
        if(argAlSf==null)
            argAlSf = new ArrayList<>();
        // 查找当前组件下有几条线
        List<SequenceFlow> sfList = Lists.newArrayList();
        for (String currTaskKey : currTaskKeys) {
            for (FlowElement flowElement : flowElements) {
                if(flowElement instanceof SequenceFlow && ((SequenceFlow) flowElement).getTargetRef().toString().equals(currTaskKey)){
                    // 判断这条栈是不是已经循环过了，如果循环过了则不在循环，必免嵌套死循环的情况出现
                    if(!argAlSf.contains(((SequenceFlow)flowElement).getId())) {
                        sfList.add((SequenceFlow)flowElement);
                        argAlSf.add(((SequenceFlow)flowElement).getId());
                    }
                }
            }
        }


        // 针对多条线儿进行循环
        for (SequenceFlow sequenceFlow : sfList) {
            String sourceRef = ((SequenceFlow) sequenceFlow).getSourceRef();
            if(!lineFilter) // 过滤掉线元素
                taskList.add(sequenceFlow);
            f:for (FlowElement flowElement : flowElements) {
                if(flowElement.getId().toString().equals(sourceRef)) {
                    if (flowElement instanceof StartEvent) {
                        taskList.add(flowElement);
                        break f;
                    } else {
                        taskList.add(flowElement);
                        // 继续向下级进行递归
                        List<String> objects = Lists.newArrayList();
                        objects.add(flowElement.getId());
                        List<FlowElement> parentUserTaskList = getParenElementList(flowElements,objects,lineFilter,argAlSf);
                        taskList.addAll(parentUserTaskList);
                    }
                }
            }
        }
        return taskList;
    }

    /**
     * 跟据当前任务，查找和它并列的任务列表（比如说会签的情况，返回的数据是会签另一个分支的所有用户任务）
     * @param flowElements
     * @param currTaskKeys
     * @param argAlSf
     * @return
     */
    public static List<UserTask> getTiedForUserTaskList(Collection<FlowElement> flowElements, String currTaskKeys,List<String> argAlSf) {
        List<UserTask> taskList = Lists.newArrayList();
        if(argAlSf==null)
            argAlSf = Lists.newArrayList();
        // 查找当前组件下有几条线
        List<SequenceFlow> sfList = Lists.newArrayList();
        for (FlowElement flowElement : flowElements) {
            if(flowElement instanceof SequenceFlow && ((SequenceFlow) flowElement).getTargetRef().toString().equals(currTaskKeys)){
                if(!argAlSf.contains(((SequenceFlow) flowElement).getId())) {
                    sfList.add((SequenceFlow)flowElement);
                    argAlSf.add(((SequenceFlow) flowElement).getId());
                }

            }
        }
        // 循环线儿
        for (SequenceFlow sequenceFlow : sfList) {
            String sourceRef = sequenceFlow.getSourceRef();
            for (FlowElement flowElement : flowElements) {
                if(flowElement.getId().toString().equals(sourceRef)) {
                    // 判断如果前一个节点是网关的话则查找网关另外几条线儿的用户节点
                    if (flowElement instanceof ParallelGateway || flowElement instanceof ExclusiveGateway) {
                        String gatewayId = flowElement.getId();
                        // 查找这个网关下的线儿，判断出来其它分支的线儿
                        List<SequenceFlow> sfList2 = Lists.newArrayList();
                        for (FlowElement flowElement2 : flowElements) {
                            if(flowElement2 instanceof SequenceFlow && ((SequenceFlow) flowElement2).getSourceRef().toString().equals(gatewayId)){
                                SequenceFlow sf =(SequenceFlow)flowElement2;
                                // 判断这条线是否是当前的线
                                boolean isExist=false;
                                f2:for (SequenceFlow flow : sfList) {
                                    if(flow.getId().equals(sf.getId())) {
                                        isExist=true;
                                        break f2;
                                    }
                                }
                                if(!isExist) {
                                    // 这是其它的线，需要找到其它线下的用户任务节点列表
                                    List<UserTask> userTasks = queryUserTaskBySequenceFlow(flowElements, sf,null);
                                    taskList.addAll(userTasks);
                                }
                            }
                        }
                    } else {
                        // 前一个节点不是网关，需要判断前一个节点是否存在用户任务
                        FlowElement currFlowElement = null;
                        for (FlowElement element : flowElements) {
                            if(element.getId().equals(currTaskKeys))
                                currFlowElement = element;
                        }
                        UserTask userTask = querySignBackUserTask(flowElements, currFlowElement);
                        if(AssertValid.isNotEmpty(userTask)) {
                            // 这里确定前一个节点是用户任务了
                            return taskList;
                        } else {
                            // 如果不是用户任务,返回当前分支下网关之前的第一个任务
                            List<FlowElement> flowElements1 = queryBeginGatewayFlowElement(flowElements, flowElement,null);
                            if(AssertValid.isNotEmpty(flowElements1)) {
                                // 继续往下找
                                List<UserTask> tiedForUserTaskList = getTiedForUserTaskList(flowElements, flowElements1.get(0).getId(),argAlSf);
                                return tiedForUserTaskList;
                            } else {
                                return Lists.newArrayList();
                            }
                        }
                    }
                }
            }
        }
        return taskList;
    }

    /**
     * 跟据任务KEY查询用户任务对像
     * @param flowElements
     * @param currTaskKeys
     * @return
     */
    public static UserTask queryUserTesk(Collection<FlowElement> flowElements, String currTaskKeys) {
        for (FlowElement flowElement : flowElements) {
            if(flowElement instanceof UserTask && flowElement.getId().equals(currTaskKeys))
                return (UserTask)flowElement;
        }
        return null;
    }
    /**
     * 获得当前分支节点最近的一个用户任务，
     * @param flowElements
     * @param fe
     * @return
     */
    public static UserTask querySignBackUserTask(Collection<FlowElement> flowElements,FlowElement fe) {
        List<SequenceFlow> sfList = Lists.newArrayList();
        for (FlowElement flowElement : flowElements) {
            if(flowElement instanceof SequenceFlow && ((SequenceFlow) flowElement).getTargetRef().toString().equals(fe.getId())){
                sfList.add((SequenceFlow)flowElement);
            }
        }
        for (SequenceFlow sequenceFlow : sfList) {
            String sourceRef = ((SequenceFlow) sequenceFlow).getSourceRef();
            for (FlowElement flowElement : flowElements) {
                if(flowElement.getId().equals(sourceRef)) {
                    if(flowElement instanceof ParallelGateway || flowElement instanceof ExclusiveGateway || flowElement instanceof ComplexGateway || flowElement instanceof InclusiveGateway) {
                        return null;
                    } else if(flowElement instanceof UserTask){
                       return (UserTask)flowElement;
                    } else {
                        // 不是网关又不是用户任务则继续往下找用户任务
                        return querySignBackUserTask(flowElements,flowElement);
                    }
                }
            }
        }
        return null;
    }

    /**
     * 返回当前元素之前，网关后的第一个任务
     * @param flowElements
     * @param fe
     * @param srgAlSf
     * @return
     */
    public static List<FlowElement> queryBeginGatewayFlowElement(Collection<FlowElement> flowElements,FlowElement fe,List<String> srgAlSf) {

        List<FlowElement> objects = Lists.newArrayList();
        List<SequenceFlow> sfList = Lists.newArrayList();
        if(srgAlSf==null)
            srgAlSf = new ArrayList<>();
        for (FlowElement flowElement : flowElements) {
            if(flowElement instanceof SequenceFlow && ((SequenceFlow) flowElement).getTargetRef().toString().equals(fe.getId())){
                // 过滤掉已经循环过的线儿
                if(!srgAlSf.contains(fe.getId())) {
                    sfList.add((SequenceFlow)flowElement);
                    srgAlSf.add(fe.getId());
                }

            }
        }
        for (SequenceFlow sequenceFlow : sfList) {
            String sourceRef = ((SequenceFlow) sequenceFlow).getSourceRef();
            f:for (FlowElement flowElement : flowElements) {
                if(flowElement.getId().equals(sourceRef)) {
                    if(flowElement instanceof ParallelGateway || flowElement instanceof ExclusiveGateway || flowElement instanceof ComplexGateway || flowElement instanceof InclusiveGateway || flowElement instanceof StartEvent) {
                        for (FlowElement element : flowElements) {
                            if(element.getId().equals(((SequenceFlow) sequenceFlow).getTargetRef())) {
                                objects.add(element);
                                break f;
                            }
                        }
                    } else {
                        // 不是网关又不是用户任务则继续往下找用户任务
                        return queryBeginGatewayFlowElement(flowElements,flowElement,srgAlSf);
                    }
                }
            }
        }
        return objects;
    }

    /**
     * 跟据线儿，查询这条线下的所有用户任务，
     * @param flowElements
     * @param sf
     * @param argAlSf
     * @return
     */
    public static List<UserTask> queryUserTaskBySequenceFlow(Collection<FlowElement> flowElements,SequenceFlow sf,List<String> argAlSf) {
        List<UserTask> taskList = Lists.newArrayList();

        for (FlowElement flowElement : flowElements) {
            // 查找到目标的用户任务
            if(flowElement.getId().equals(sf.getTargetRef())) {
                if(flowElement instanceof UserTask) {
                    taskList.add((UserTask)flowElement);
                }
                if(flowElement instanceof EndEvent){
                    // 遇到网关、终止事件返回数据
                    return taskList;
                }
                // 不是终
                for (FlowElement flowElement2 : flowElements) {
                    List<SequenceFlow> sfList2 = new ArrayList<>();
                    if(flowElement2 instanceof SequenceFlow && ((SequenceFlow) flowElement2).getSourceRef().equals(flowElement.getId())) {
                        // 这里跟据线儿在往下找用户任务
                        if(argAlSf==null) {
                            argAlSf = new ArrayList<>();
                        } else {
                            if(!argAlSf.contains(flowElement.getId())) {
                                List<UserTask> userTasks = queryUserTaskBySequenceFlow(flowElements, (SequenceFlow) flowElement2,argAlSf);
                                taskList.addAll(userTasks);
                                argAlSf.add(flowElement.getId());
                            }
                        }


                    }
                }

            }
        }
        return taskList;
    }

}